package cn.xd.base.application.service.query.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.xd.base.application.assembler.AdminOrgAssembler;
import cn.xd.base.application.assembler.AdminOrgRoleAssembler;
import cn.xd.base.application.assembler.AdminRoleAssembler;
import cn.xd.base.application.assembler.AdminRoleDetailAssembler;
import cn.xd.base.application.dto.query.AdminOrgRoleQuery;
import cn.xd.base.application.dto.query.AdminRoleQuery;
import cn.xd.base.application.service.query.AdminRoleQueryAppService;
import cn.xd.base.basic.type.AdminOrgId;
import cn.xd.base.basic.type.AdminRoleId;
import cn.xd.base.domain.bean.response.AdminOrgRoleDTO;
import cn.xd.base.domain.bean.response.AdminRoleDTO;
import cn.xd.base.domain.bean.response.AdminRoleDetailDTO;
import cn.xd.base.domain.entity.AdminOrg;
import cn.xd.base.domain.entity.AdminRole;
import cn.xd.base.domain.repository.AdminRoleRepository;
import cn.xd.base.persistence.dos.AdminOrgConverter;
import cn.xd.base.persistence.dos.AdminOrgRoleDO;
import cn.xd.base.persistence.dos.AdminRoleConverter;
import cn.xd.base.persistence.dos.AdminRoleDO;
import cn.xd.base.persistence.mps.AdminOrgMpService;
import cn.xd.base.persistence.mps.AdminOrgRoleMpService;
import cn.xd.base.persistence.mps.AdminRoleMpService;
import cn.xd.common.enums.common.CommonStatusEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class AdminRoleQueryAppServiceImpl implements AdminRoleQueryAppService {
    @Resource
    private AdminRoleMpService adminRoleMpService;
    @Resource
    private AdminOrgMpService adminOrgMpService;
    @Resource
    private AdminOrgRoleMpService adminOrgRoleMpService;
    @Resource
    private AdminRoleRepository adminRoleRepository;

    @Override
    public Page<AdminRoleDTO> getPage(AdminRoleQuery query, List<Long> orgIds) {
        List<Long> ids = getRoleIdsByOrgIds(orgIds);
        if (CollUtil.isEmpty(ids)) {
            return new Page<>();
        }
        List<Long> roleIds = new ArrayList<>();
        if (CollUtil.isNotEmpty(query.getOrgIds())) {
            roleIds = getRoleIdsByOrgIds(query.getOrgIds());
            if (CollUtil.isEmpty(roleIds)) {
                return new Page<>();
            }
        }
        return adminRoleMpService.getPage(new LambdaQueryWrapper<AdminRoleDO>()
                        .like(StrUtil.isNotBlank(query.getName()), AdminRoleDO::getName, query.getName())
                        .in(CollUtil.isNotEmpty(roleIds), AdminRoleDO::getId, roleIds)
                        .ne(AdminRoleDO::getStatus, CommonStatusEnum.DELETED.getCode())
                        .in(AdminRoleDO::getId, ids)
                        .orderByDesc(AdminRoleDO::getId)
                , AdminRoleAssembler.INSTANCE, query);
    }

    @Override
    public List<AdminRoleDTO> getList(AdminRoleQuery query, List<Long> orgIds) {
        List<Long> ids = getRoleIdsByOrgIds(orgIds);
        if (CollUtil.isEmpty(ids)) {
            return new ArrayList<>();
        }
        List<Long> roleIds = new ArrayList<>();
        if (CollUtil.isNotEmpty(query.getOrgIds())) {
            roleIds = getRoleIdsByOrgIds(query.getOrgIds());
            if (CollUtil.isEmpty(roleIds)) {
                return new ArrayList<>();
            }
        }
        List<AdminRoleDO> list = adminRoleMpService.lambdaQuery()
                .like(StrUtil.isNotBlank(query.getName()), AdminRoleDO::getName, query.getName())
                .in(CollUtil.isNotEmpty(query.getOrgIds()), AdminRoleDO::getId, roleIds)
                .ne(AdminRoleDO::getStatus, CommonStatusEnum.DELETED.getCode())
                .in(AdminRoleDO::getId, ids)
                .orderByDesc(AdminRoleDO::getId).list();
        return AdminRoleAssembler.INSTANCE.fromData(list);
    }

    public List<Long> getRoleIdsByOrgIds(List<Long> orgIds) {
        if (CollUtil.isEmpty(orgIds)) {
            return new ArrayList<>();
        }
        return adminOrgRoleMpService.lambdaQuery().in(AdminOrgRoleDO::getOrgId, orgIds).list()
                .stream().map(AdminOrgRoleDO::getRoleId).toList();
    }

    public List<Long> getRoleIdsByOrgId(Long orgId) {
        if (ObjUtil.isEmpty(orgId)) {
            return new ArrayList<>();
        }
        return adminOrgRoleMpService.lambdaQuery().eq(AdminOrgRoleDO::getOrgId, orgId).list()
                .stream().map(AdminOrgRoleDO::getRoleId).toList();
    }

    @Override
    public AdminRoleDetailDTO getInfo(Long id) {
        AdminRole adminRole = adminRoleRepository.find(AdminRoleId.of(id)).isEmptyThrow("未找到该角色");
        return AdminRoleDetailAssembler.INSTANCE.toDTO(adminRole);
    }

    @Override
    public Boolean checkHasName(String name, Long id) {
        return ObjUtil.isNotEmpty(adminRoleMpService.getAdminRole(name, id));
    }

    @Override
    public Page<AdminOrgRoleDTO> getAdminOrgRolePage(AdminOrgRoleQuery query, List<Long> orgIds) {
        Page<AdminOrgRoleDO> page = adminOrgRoleMpService.getPage(Wrappers.lambdaQuery(AdminOrgRoleDO.class)
                        .in(CollUtil.isNotEmpty(query.getOrgIds()), AdminOrgRoleDO::getOrgId, query.getOrgIds())
                        .in(AdminOrgRoleDO::getOrgId, orgIds).orderByDesc(AdminOrgRoleDO::getRoleId)
                , query);
        List<AdminOrgRoleDTO> result = new ArrayList<>();
        for (AdminOrgRoleDO record : page.getRecords()) {
            AdminRole adminRole = adminRoleMpService.getResult(AdminRoleId.of(record.getRoleId()), AdminRoleConverter.INSTANCE).get();
            AdminOrg adminOrg = adminOrgMpService.getResult(AdminOrgId.of(record.getOrgId()), AdminOrgConverter.INSTANCE).get();
            if (ObjUtil.isEmpty(adminOrg) || ObjUtil.isEmpty(adminRole)
                    || !adminOrg.getStatus().getValue().equals(CommonStatusEnum.ENABLE.getCode())
                    || !adminRole.getStatus().getValue().equals(CommonStatusEnum.ENABLE.getCode())) {
                result.add(new AdminOrgRoleDTO());
                continue;
            }
            AdminOrgRoleDTO dto = new AdminOrgRoleDTO();
            dto.setId(record.getId());
            dto.setRole(AdminRoleAssembler.INSTANCE.toDTO(adminRole));
            dto.setOrg(AdminOrgAssembler.INSTANCE.toDTO(adminOrg));
            result.add(dto);
        }
        Page<AdminOrgRoleDTO> res = (Page<AdminOrgRoleDTO>) page.convert(AdminOrgRoleAssembler.INSTANCE::fromData);
        res.setRecords(result);
        return res;
    }
}
